data.head()
| car_ID | symboling | CarName | fueltype | aspiration | doornumber | carbody | drivewheel | enginelocation | wheelbase | ... | enginesize | fuelsystem | boreratio | stroke | compressionratio | horsepower | peakrpm | citympg | highwaympg | price | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 3 | alfa-romero giulia | gas | std | two | convertible | rwd | front | 88.6 | ... | 130 | mpfi | 3.47 | 2.68 | 9.0 | 111 | 5000 | 21 | 27 | 13495.0 |
| 1 | 2 | 3 | alfa-romero stelvio | gas | std | two | convertible | rwd | front | 88.6 | ... | 130 | mpfi | 3.47 | 2.68 | 9.0 | 111 | 5000 | 21 | 27 | 16500.0 |
| 2 | 3 | 1 | alfa-romero Quadrifoglio | gas | std | two | hatchback | rwd | front | 94.5 | ... | 152 | mpfi | 2.68 | 3.47 | 9.0 | 154 | 5000 | 19 | 26 | 16500.0 |
| 3 | 4 | 2 | audi 100 ls | gas | std | four | sedan | fwd | front | 99.8 | ... | 109 | mpfi | 3.19 | 3.40 | 10.0 | 102 | 5500 | 24 | 30 | 13950.0 |
| 4 | 5 | 2 | audi 100ls | gas | std | four | sedan | 4wd | front | 99.4 | ... | 136 | mpfi | 3.19 | 3.40 | 8.0 | 115 | 5500 | 18 | 22 | 17450.0 |
5 rows × 26 columns
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 205 entries, 0 to 204 Data columns (total 26 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 car_ID 205 non-null int64 1 symboling 205 non-null int64 2 CarName 205 non-null object 3 fueltype 205 non-null object 4 aspiration 205 non-null object 5 doornumber 205 non-null object 6 carbody 205 non-null object 7 drivewheel 205 non-null object 8 enginelocation 205 non-null object 9 wheelbase 205 non-null float64 10 carlength 205 non-null float64 11 carwidth 205 non-null float64 12 carheight 205 non-null float64 13 curbweight 205 non-null int64 14 enginetype 205 non-null object 15 cylindernumber 205 non-null object 16 enginesize 205 non-null int64 17 fuelsystem 205 non-null object 18 boreratio 205 non-null float64 19 stroke 205 non-null float64 20 compressionratio 205 non-null float64 21 horsepower 205 non-null int64 22 peakrpm 205 non-null int64 23 citympg 205 non-null int64 24 highwaympg 205 non-null int64 25 price 205 non-null float64 dtypes: float64(8), int64(8), object(10) memory usage: 41.8+ KB
data.describe()
| car_ID | symboling | wheelbase | carlength | carwidth | carheight | curbweight | enginesize | boreratio | stroke | compressionratio | horsepower | peakrpm | citympg | highwaympg | price | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 | 205.000000 |
| mean | 103.000000 | 0.834146 | 98.756585 | 174.049268 | 65.907805 | 53.724878 | 2555.565854 | 126.907317 | 3.329756 | 3.255415 | 10.142537 | 104.117073 | 5125.121951 | 25.219512 | 30.751220 | 13276.710571 |
| std | 59.322565 | 1.245307 | 6.021776 | 12.337289 | 2.145204 | 2.443522 | 520.680204 | 41.642693 | 0.270844 | 0.313597 | 3.972040 | 39.544167 | 476.985643 | 6.542142 | 6.886443 | 7988.852332 |
| min | 1.000000 | -2.000000 | 86.600000 | 141.100000 | 60.300000 | 47.800000 | 1488.000000 | 61.000000 | 2.540000 | 2.070000 | 7.000000 | 48.000000 | 4150.000000 | 13.000000 | 16.000000 | 5118.000000 |
| 25% | 52.000000 | 0.000000 | 94.500000 | 166.300000 | 64.100000 | 52.000000 | 2145.000000 | 97.000000 | 3.150000 | 3.110000 | 8.600000 | 70.000000 | 4800.000000 | 19.000000 | 25.000000 | 7788.000000 |
| 50% | 103.000000 | 1.000000 | 97.000000 | 173.200000 | 65.500000 | 54.100000 | 2414.000000 | 120.000000 | 3.310000 | 3.290000 | 9.000000 | 95.000000 | 5200.000000 | 24.000000 | 30.000000 | 10295.000000 |
| 75% | 154.000000 | 2.000000 | 102.400000 | 183.100000 | 66.900000 | 55.500000 | 2935.000000 | 141.000000 | 3.580000 | 3.410000 | 9.400000 | 116.000000 | 5500.000000 | 30.000000 | 34.000000 | 16503.000000 |
| max | 205.000000 | 3.000000 | 120.900000 | 208.100000 | 72.300000 | 59.800000 | 4066.000000 | 326.000000 | 3.940000 | 4.170000 | 23.000000 | 288.000000 | 6600.000000 | 49.000000 | 54.000000 | 45400.000000 |
data.shape
(205, 26)
On peut constater qu'on a peu de lignes et beaucoup de colonnes
data.isna().sum()
car_ID 0 symboling 0 CarName 0 fueltype 0 aspiration 0 doornumber 0 carbody 0 drivewheel 0 enginelocation 0 wheelbase 0 carlength 0 carwidth 0 carheight 0 curbweight 0 enginetype 0 cylindernumber 0 enginesize 0 fuelsystem 0 boreratio 0 stroke 0 compressionratio 0 horsepower 0 peakrpm 0 citympg 0 highwaympg 0 price 0 dtype: int64
data.duplicated().sum()
0
data['doornumber'].value_counts()
four 115 two 90 Name: doornumber, dtype: int64
data['doornumber'].value_counts()
4 115 2 90 Name: doornumber, dtype: int64
On a pu constater qu'il n'y avait que 2 valeurs uniques en chaine de caractères qui correspondait à des chiffres. Pour facilité l'analyse, on a remplacé par les chiffres
sns.heatmap(data.corr(), annot=True, fmt=".1f")
<AxesSubplot:>
Avec le heatmap on peut voir que plusieurs valeurs semblent impacter le prix de la voiture
sns.scatterplot(data=data, x="price", y="enginesize", size="horsepower").set(title="Prix d'une voiture en fonction de la taille du moteur et de la puissance en chevaux");
Plus le prix augmente, plus la taille des points semble augmenter (ce qui correspond à la puissance en chevaux) La taille du moteur semble aussi augmenter avec le prix, on obtient un graphique qui à l'air linéaire
sns.scatterplot(data=data, x="price", y="carwidth").set(title="Prix d'une voiture en fonction de la largeur de la voiture");
Quand le prix est plus faible, les points sont plus condensés et au même endroit. Jusqu'au prix de 25000 la relation a l'air plutôt linéaire mais au dessus, les points sont plus éparpillés ce qui peut créer des erreurs
sns.scatterplot(data=data, x="price", y="curbweight").set(title="Prix de la voiture en fonction du poids à vide");
On obtient un graphique assez similaire au précédent, où au dessus de 25000 le poids à vide de la voiture ne semble plus avoir trop d'impact
plt.pie(data['fueltype'].value_counts(), labels=data['fueltype'].unique(), autopct='%.0f%%')
plt.title("Pourcentage du type de carburant")
plt.show()
On peut remarquer que 90% des voitures sont au gasoil et donc prendre cette feature en compte et sûrement peu signicative car pas assez de données
sns.scatterplot(data=data, x="price", y="enginesize", hue="curbweight", size="horsepower").set(title= "Prix d'une voiture en fonction de la taille du moteur, la puissance en chevaux et le poids à vide");
On remarque bien que de manière générale le prix augmente bien avec les features, même s'il y a quelques zones où cela se confond
plt.hist(data['price'])
plt.xlabel('Price')
plt.ylabel('Count')
plt.title('Prix des voitures')
plt.show()
On remarque que la majorité des voitures ont un prix inférieur à 25000
plt.hist(data['enginesize'])
plt.xlabel('Enginesize')
plt.ylabel('Count')
plt.title('Distribution de la taille du moteur')
plt.show()
import plotly.express as px
fig = px.scatter_3d(data, x="price", y="enginesize", z="curbweight", color="carwidth", size="horsepower")
fig.show()
Graphique en 3d avec les features analysées précédemment. On remarque bien la forte concentration de points lorsque le prix est faible
y = data.price
X = data[['enginesize']]
model.score(X_test_scaled, y_test)
0.7726894661645483
y_2 = data.price
X_2 = data[['enginesize', 'curbweight', 'horsepower']]
model.score(X_test_scaled_2, y_test_2)
0.7858734070212768
On remarque que le score est légèrement supérieur
cross_val_score(model, X, y, cv=3)
array([0.73047413, 0.79655265, 0.44822534])
cross_val_score(model, X_2, y_2, cv=3)
array([0.7933756 , 0.7612985 , 0.58043235])
Le score est également plus élevé avec les 3 features, comme il y a ~200 lignes dans le dataset on ne peut pas faire énormément de fold
residus = y_predict_2 - y_test_2
sns.histplot(residus, bins=15, kde=True).set(title="Distribution des résidus");
La distribution des résidus semble suivre une loi normale
plt.scatter(y_predict_2, residus, label="residuals")
plt.plot([4000,35000], [0,0], c='r', label="null-error line")
plt.xlabel('Predicted car price')
plt.ylabel('Residuals')
plt.title('Répartition des résidus')
plt.legend()
plt.show()
La répartition des résidus ne semble pas homoscédastique